#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/uaccess.h>
#include <linux/i2c.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/gpio.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_gpio.h>
#include <linux/device.h>
#include <linux/time.h>

#include <linux/platform_device.h>
#include <linux/spi/spi.h>
#include "SPI.h"

#define DevName "SPI_device"
#define ClassName "SPI_calss"

struct spi_device *flash_spi_device = NULL;
static dev_t devno;
static struct cdev chardev_str; // 字符设备结构体
static struct class* spi_class;
static struct device* spi_dev;

static unsigned char ReadBuff[4096] = {1,2,3,4,5,6,7,8,9};
static unsigned char WriteBuff[256] = {0};

//发送一条指令
static int flash_spi_send_command(struct spi_device* spi_device, u8 command)
{
	int error = 0;
	u8 tx_data = command;
	struct spi_message *message;   //定义发送的消息
	struct spi_transfer *transfer; //定义传输结构体

	/*申请空间*/
	message = kzalloc(sizeof(struct spi_message), GFP_KERNEL);
	transfer = kzalloc(sizeof(struct spi_transfer), GFP_KERNEL);

	/*填充message和transfer结构体*/
	transfer->tx_buf = &tx_data;
	transfer->len = 1;
	spi_message_init(message);
	spi_message_add_tail(transfer, message);

	error = spi_sync(spi_device, message);
	kfree(message);
	kfree(transfer);
	if (error != 0)
	{
		printk("spi_sync error! \n");
		return -1;
	}
	return 0;
}

//发送许多指令
static int flash_spi_send_commands(struct spi_device* spi_device, unsigned char* command, int length)
{
	int error = 0;
	int i = 0;
	u8 tx_data = 0;
	struct spi_message *message;   //定义发送的消息
	struct spi_transfer *transfer; //定义传输结构体

	/*申请空间*/
	message = kzalloc(sizeof(struct spi_message), GFP_KERNEL);
	transfer = kzalloc(sizeof(struct spi_transfer), GFP_KERNEL);
	// for (i = 0; i < length; i++){
	// 	tx_data = command[i];
	// 	transfer->tx_buf = &tx_data;
	// 	transfer->len = 1;
	// 	spi_message_init(message);
	// 	spi_message_add_tail(transfer, message);
	// 	error = spi_sync(spi_device, message);
	// }
	transfer->tx_buf = command;
	transfer->len = length;
	spi_message_init(message);
	spi_message_add_tail(transfer, message);
	error = spi_sync(spi_device, message);
	kfree(message);
	kfree(transfer);
	if (error != 0){
		printk("spi_sync error! \n");
		return -1;
	}
	return 0;
}

//发送许多数据
static int flash_spi_send_datas(struct spi_device* spi_device, unsigned char* data, int length)
{
	int error = 0;
	int index = 0;
	struct spi_message *message;   //定义发送的消息
	struct spi_transfer *transfer; //定义传输结构体
	unsigned char pre_data[] = {PageProgram, 0x0, 0x0, 0x0};

	/*申请空间*/
	message = kzalloc(sizeof(struct spi_message), GFP_KERNEL);
	transfer = kzalloc(sizeof(struct spi_transfer), GFP_KERNEL);

	/*填充message和transfer结构体*/
	transfer->tx_buf = pre_data;
	transfer->len = 4;
	spi_message_init(message);
	spi_message_add_tail(transfer, message);

	error = spi_sync(spi_device, message);

	/*每次发送 30字节，循环发送*/
	do {
		if (length > 30){
			transfer->tx_buf = data + index;
			transfer->len = 30;
			spi_message_init(message);
			spi_message_add_tail(transfer, message);
			index += 30;
			length -= 30;
		}else{
			transfer->tx_buf = data + index;
			transfer->len = length;
			spi_message_init(message);
			spi_message_add_tail(transfer, message);
			index += length;
			length = 0;
		}
		error = spi_sync(spi_device, message);
		if (error != 0){
			printk("spi_sync error! %d \n", error);
			return -1;
		}
	}while (length > 0);

	kfree(message);
	kfree(transfer);
	return 0;
}

//读取数据
static int flash_spi_read_datas(struct spi_device* spi_device, u32 add, int length)
{
	int error = 0;
	int i = 0;
	unsigned char tx_data[10] = {0};
	//unsigned char rx_data = 0;
	unsigned char addr[] = {ReadData, 0x0, 0x0, 0x0};
	struct spi_message *message;   //定义发送的消息
	struct spi_transfer *transfer; //定义传输结构体

	/*申请空间*/
	message = kzalloc(sizeof(struct spi_message), GFP_KERNEL);
	transfer = kzalloc(sizeof(struct spi_transfer), GFP_KERNEL);

	// 发送需要读取数据的地址
	transfer->tx_buf = &addr;
	transfer->len = 4;
	spi_message_init(message);
	spi_message_add_tail(transfer, message);
	error = spi_sync(spi_device, message);
	if (error != 0)	{
		printk("spi_sync error! \n");
		return -1;
	}

	// 开始读取数据
	// for(i = 0; i < length; i++) {
	// 	transfer->tx_buf = &tx_data;
	// 	transfer->rx_buf = &rx_data;
	// 	transfer->len = 1;
	// 	spi_message_init(message);
	// 	spi_message_add_tail(transfer, message);
	// 	ReadBuff[i] = rx_data;
	// }
	// error = spi_sync(spi_device, message);

	transfer->tx_buf = tx_data;
	transfer->rx_buf = ReadBuff;
	transfer->len = 10;
	spi_message_init(message);
	spi_message_add_tail(transfer, message);
	error = spi_sync(spi_device, message);


	if (error != 0)	{
		printk("spi_sync error! \n");
		return -1;
	}
	kfree(message);
	kfree(transfer);
	return 0;
}


void flash_spi_erase(void)
{
	unsigned char data[] = {SectorErase, 0x0, 0x0, 0x0};
	//擦除4K，即一个扇区，擦除的最小单位是扇区
	flash_spi_send_commands(flash_spi_device, data, sizeof(data));//发送扇区擦除指令及扇区地址地址
	printk("flash erase finish!\n");
}

static int flash_spi_open(struct inode *inode, struct file *filp)
{
	int i = 0;
	flash_spi_send_command(flash_spi_device, ReleasePowerDown);//发送掉电复位信号
	msleep(1000);
	flash_spi_erase();
	flash_spi_read_datas(flash_spi_device, 0x00, 4096);
	printk("the data in addr 0x0 is ...\n");
	for(i = 0; i < 4096; i++){
		printk("0x%02x ", ReadBuff[i]);
	}
	return 0;
}

static int flash_spi_close(struct inode *inode, struct file *filp)
{
	flash_spi_send_command(flash_spi_device, PowerDown);//发送掉电信号
	return 0;
}


static struct file_operations SPI_fops = {
	.owner = THIS_MODULE,
	.open = flash_spi_open, 
	.release = flash_spi_close
};


static int spi_probe(struct spi_device *spi)
{
    int ret = -1; //保存错误状态码
	int i = 0;
    // 设置spi，可以从设备树中读取得到(of函数)
	printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);;
    flash_spi_device = spi;
    flash_spi_device->mode = SPI_MODE_0;
    flash_spi_device->max_speed_hz = 2000000;
    spi_setup(flash_spi_device);

    ret = alloc_chrdev_region(&devno, 0, 1, DevName);
    if (ret < 0){
        printk(" fail to alloc SPI devno\n");
    }
    cdev_init(&chardev_str, &SPI_fops);
    chardev_str.owner = THIS_MODULE;
    ret = cdev_add(&chardev_str, devno, 1);
    if (ret < 0){
        printk(" fail to add SPI cdev\n");
    }
    spi_class = class_create(THIS_MODULE, ClassName);
    spi_dev = device_create(spi_class, NULL, devno, NULL, DevName);

	/*打印spi_device 部分内容*/
	printk("max_speed_hz = %d\n", flash_spi_device->max_speed_hz);
	//printk("chip_select = %d\n", (int)flash_spi_device->chip_select);
	//printk("bits_per_word = %d\n", (int)flash_spi_device->bits_per_word);
	printk("mode = %02X\n", flash_spi_device->mode);
	//printk("cs_gpio = %02X\n", flash_spi_device->cs_gpio);


	flash_spi_send_command(flash_spi_device, ReleasePowerDown);//发送掉电复位信号
	msleep(1000);
	flash_spi_send_command(flash_spi_device, WriteEnable);//发送写使能指令
	flash_spi_erase();                                         //擦除
	flash_spi_read_datas(flash_spi_device, 0x0, 10);
	printk("the value in ReadBuff\n");
	for(i = 0;i<10;i++){
        printk("0x%02x ",ReadBuff[i]);
    }
	for (i=0; i<256; i++){
		WriteBuff[i] = i;
	}
	flash_spi_send_command(flash_spi_device, W25X_WriteEnable);//发送写使能指令
	flash_spi_send_datas(flash_spi_device, WriteBuff, 10);
	msleep(1000);
	flash_spi_read_datas(flash_spi_device, 0x0, 10);
	for(i = 0;i<10;i++){
        printk("0x%02x ",ReadBuff[i]);
    }

	flash_spi_send_command(flash_spi_device, PowerDown);//发送掉电复位信号

    return 0;
}

static int spi_remove(struct spi_device *spi)
{
	cdev_del(&chardev_str);				  //清除设备号
	unregister_chrdev_region(devno, 1);  //取消注册字符设备
    device_destroy(spi_class, devno);	  //清除设备
    class_destroy(spi_class);		      //清除类
    printk("SPI exit finished! \n");
	return 0;    
}


/*指定 ID 匹配表*/
static const struct spi_device_id oled_device_id[] = {
	{"fire,ecspi_oled", 0},
	{}};

/*指定设备树匹配表*/
static const struct of_device_id spi_device_of_match_table[] = {
	{.compatible = "chengreen,flash"},
	{}};

struct spi_driver spi_driver = {
	.probe = spi_probe,
	.remove = spi_remove,
	.id_table = oled_device_id,
	.driver = {
		.name = "spi",
		.owner = THIS_MODULE,
		.of_match_table = spi_device_of_match_table,
	},
};

static int __init spi_driver_init(void)
{
	int error;
	pr_info("spi_driver_init\n");
	error = spi_register_driver(&spi_driver);
    if (error < 0){
        printk("spi register driver failed!\n");
    }
	return error;
}

static void __exit spi_driver_exit(void)
{
	pr_info("spi_driver_exit\n");
	spi_unregister_driver(&spi_driver);
}

module_init(spi_driver_init);
module_exit(spi_driver_exit);

MODULE_LICENSE("GPL");